#include "WinAudioRender.h"

#include <Audioclient.h>

#include <mmdeviceapi.h>
#include <avrt.h>

#include <QDebug>

WinAudioRender::WinAudioRender(QObject *parent, const QString mediaId) : QObject(parent),m_deviceId(mediaId)
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (hr == S_FALSE) {
        qDebug() << "mic com init already";
    }
}

void WinAudioRender::run()
{
    IMMDevice* pDevice = NULL;
    IMMDeviceEnumerator *pMMDeviceEnumerator = NULL;
    HRESULT hr = CoCreateInstance(
                __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
                __uuidof(IMMDeviceEnumerator),
                (void**)&pMMDeviceEnumerator
                );
    if(FAILED(hr)) qDebug() << "error";

    if (m_deviceId.isEmpty())
        hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
    else
        hr = pMMDeviceEnumerator->GetDevice(m_deviceId.toStdWString().c_str(),&pDevice);

    if (FAILED(hr)) qDebug() << "error";

    pMMDeviceEnumerator->Release();

    IAudioClient *pAudioClient = NULL;
    WAVEFORMATEX *pwfx = NULL;
    IAudioRenderClient *pAudioRenderClient = NULL;
    DWORD nTaskIndex = 0;
    HANDLE hTask = NULL;
    BOOL bStarted(FALSE);
    UINT32 nFrameBufferSize(0);
    HANDLE hEventRequestData = NULL;
    do {
        hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
        if(FAILED(hr)) break;

        hr = pAudioClient->GetMixFormat(&pwfx);
        if (FAILED(hr)) break;

        hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, pwfx, 0);
        if(FAILED(hr)) break;

        hr = pAudioClient->GetBufferSize(&nFrameBufferSize);
        if(FAILED(hr)) break;

        hr = pAudioClient->GetService(__uuidof(IAudioRenderClient), (void**)&pAudioRenderClient);
        if(FAILED(hr)) break;

        hTask = AvSetMmThreadCharacteristics(L"Playback", &nTaskIndex);
        if (NULL == hTask) break;

        hEventRequestData = CreateEvent(NULL, FALSE, FALSE, NULL);
        if(hEventRequestData == NULL) break;

        hr = pAudioClient->SetEventHandle(hEventRequestData);
        if(FAILED(hr)) break;

        hr = pAudioClient->Start();
        if(FAILED(hr)) break;

        bStarted = TRUE;

        HANDLE m_hEventStop = CreateEvent(NULL, TRUE, FALSE, NULL);

        HANDLE waitArray[2] = { m_hEventStop, hEventRequestData };
        DWORD dwWaitResult;
        BYTE *pData = NULL;
        UINT32 nFramesOfPadding(0);
        UINT nNeedDataLen(0);
        while(TRUE) {
            dwWaitResult = WaitForMultipleObjects(sizeof(waitArray)/sizeof(waitArray[0]), waitArray, FALSE, INFINITE);
            if(WAIT_OBJECT_0 == dwWaitResult) break;

            if (WAIT_OBJECT_0 + 1 != dwWaitResult){
                break;
            }

            hr = pAudioClient->GetCurrentPadding(&nFramesOfPadding);
            if(FAILED(hr)) break;

            if(nFrameBufferSize == nFramesOfPadding) continue;

            nNeedDataLen = nFrameBufferSize - nFramesOfPadding;
            hr = pAudioRenderClient->GetBuffer(nNeedDataLen, &pData);
            if(FAILED(hr))break;

            /* 这里什么也不做，可以保持静音状态 */
            pAudioRenderClient->ReleaseBuffer(nNeedDataLen, 0);
        }

    }while(FALSE);

    if(hEventRequestData != NULL) {
        CloseHandle(hEventRequestData);
        hEventRequestData = NULL;
    }

    if(hTask != NULL) {
        AvRevertMmThreadCharacteristics(hTask);
        hTask = NULL;
    }

    if(pAudioRenderClient != NULL) {
        pAudioRenderClient->Release();
        pAudioRenderClient = NULL;
    }

    if(pwfx != NULL) {
        CoTaskMemFree(pwfx);
        pwfx = NULL;
    }

    if(pAudioClient != NULL) {
        if(bStarted) {
            pAudioClient->Stop();
        }

        pAudioClient->Release();
        pAudioClient = NULL;
    }
}
